package commons.params.ihm;

import commons.io.in.Data_in;
import commons.params.A_ParamsManager;
import java.awt.Color;
import java.awt.Container;
import java.io.File;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;


public abstract class A_DlgParams extends javax.swing.JDialog {

	// Si la dlg contient des Tab Pane
	// Label pour affichage perso (changement de couleurs etc) des TAB
	protected int NB_TAB = 0;
	protected JLabel[] list_labelTab;

	protected Data_in dataIn;
	protected A_ParamsManager paramsManager;
	public static Color COLOR_VALID = Color.BLACK;
	public static Color COLOR_INVALID = Color.RED;

	boolean bIsthereError;

	boolean bUserHasCanceled;
	public boolean hasUserCanceled() {return bUserHasCanceled;}

	// GESTION DES EVENEMENTS
	// true pendant l'initialisation ou le remplissage de la Dialog, pour éviter
	//  des appels incessant à traiteModifUtilisateur(), qui eux meme mettent à jour l'affichage
	private boolean bStopHandleEvents;
	public void STOP_HANDLE_EVENTS() {bStopHandleEvents=true;}
	public void START_HANDLE_EVENTS() {bStopHandleEvents=false;}
	public boolean IS_STOPPING_EVENTS() {return bStopHandleEvents;}

	
	public A_DlgParams() {
        initComponents();
    }
	public A_DlgParams(java.awt.Frame parent, boolean modal) {
		super(parent, modal);
		initComponents();
    }

	// Le combo qui affiche les paramètres pré-enregistrés par l'utilisateur
	abstract protected JComboBox getComboBoxStoredParams();
	// Divers boutons
	abstract protected JButton getSaveButton();
	abstract protected JButton getSaveAsButton();
	abstract protected JButton getNewParamsButton();
	// Le bouton qui valide la dialogue
	abstract protected JButton getGoButton();
	// Le bouton qui annule le traitement
	abstract protected JButton getCancelButton();
	// L'éventuel tabbed pane principal
	abstract protected JTabbedPane getTabbedPane();

	// A Appeler apres le constructor
	// En paramètre, un Data_in = les données brutes lues dans le répertoire d'entrée
	public void initialize(Data_in dataIn, A_ParamsManager paramsManager, String lastParamNameUsed) {
		this.dataIn = dataIn;
		this.paramsManager = paramsManager;

		// On stoppe la mécanique d'échange de données avec le Params pendant l'initialisation
		STOP_HANDLE_EVENTS();

		// Initiliasation de l'IHM :
		//  traitement lorsque le combo des params pre-enregistre est manipule par l'utilisateur
		getComboBoxStoredParams().addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                combo_ListStoredParamsActionPerformed(evt);
            }
        });
        getGoButton().addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_GoActionPerformed(evt);
            }
        });
        getCancelButton().addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_CancelActionPerformed(evt);
            }
        });
		getNewParamsButton().addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_NewParamsActionPerformed(evt);
            }
        });
        getSaveAsButton().addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_SaveAsActionPerformed(evt);
            }
        });
		getSaveButton().addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_SaveActionPerformed(evt);
            }
        });
		//  init du tabbed pane éventuel
		initTab();

		// Initialisation du Combo de choix des fichiers de paramétrage précédemment enregistrés
		// on est déjà en mode "Stop du traitement des évenements", comme exigé par 'updateComboListStoredParams()'
		updateComboListStoredParams();

		// On commence avec des paramètes vierges
		// cf. le combo des fichiers de param est forcément vide à l'init
		paramsManager.loadParams("");

		// L'utilisateur peut maintenant éditer les paramètres
		START_HANDLE_EVENTS();
		
		if (lastParamNameUsed != null)
			getComboBoxStoredParams().setSelectedItem(lastParamNameUsed);
	}


	private void initTab() {
		if (getTabbedPane()==null) return;

		// Creation des labels personalisés pour l'affichage des TAB
		// On pourra ainsi changer leur couleur si les param sont invalides
		NB_TAB = getTabbedPane().getTabCount();
		list_labelTab = new JLabel[NB_TAB];
		for (int i = 0; i <NB_TAB ; i++) {
			list_labelTab[i] = new JLabel(getTabbedPane().getTitleAt(i));
			getTabbedPane().setTabComponentAt(i, list_labelTab[i]);
		}
	}


	// Appelé par le paramManager après que tout les paramètres ont été écrit dans la dlg
	//  -> permet de faire des éventuels post-traitements
	public void allParamsWritten() {
		
	}

	//**************************************************************************
	//***** Gestion paramètres pré-enregistrés                           *******
	//**************************************************************************

	// ATTENTION, l'appelant doit avoir stoppé le traitement des evenements
	private void updateComboListStoredParams() {
		JComboBox combo_ListStoredParams = getComboBoxStoredParams();

		// sauvegarde de l'ancienne éventuelle valeur sélectionnée
		Object oldValue = combo_ListStoredParams.getSelectedItem();

		combo_ListStoredParams.removeAllItems();
		combo_ListStoredParams.addItem("");
		File rep = new File(paramsManager.getDirectoryUserParams());
		File[] listeAllFiles = rep.listFiles();
		if (listeAllFiles != null) {
			for (int i=0 ; i<listeAllFiles.length ; i++) {
				File f = listeAllFiles[i];
				if (f.isFile() && f.getName().endsWith(".ini")) {
					String nameWithoutExt = f.getName();
					if (nameWithoutExt.endsWith(".ini"))
						nameWithoutExt = nameWithoutExt.substring(0, nameWithoutExt.length()-4);
					combo_ListStoredParams.addItem(nameWithoutExt);
				}
			}
		}

		// restauration eventuelle de l'ancienne valeur sélectionnée
		if (oldValue!=null) combo_ListStoredParams.setSelectedItem(oldValue);
	}


	private void combo_ListStoredParamsActionPerformed(java.awt.event.ActionEvent evt) {
		if (IS_STOPPING_EVENTS())
			// on est en mode d'initialisation de la Dialog
			return;

		String paramNameChosen = getComboBoxStoredParams().getSelectedItem().toString();

		// Chargement d'un nouveau fichier de paramètres ?
		if (paramNameChosen.equals(paramsManager.getName()))
			// Pas de changement de nom, on sort
			return;

		// Y a-t-il eu des modif depuis la dernière sauvegarde ?
		if (paramsManager.hasEditUnsaved()) {

			// On demande si l'utilisateur veut sauvegarder ses modif avant le chargement du nouveau fichier
			int reponse = JOptionPane.showConfirmDialog(
					this,
					"Vous êtes sur le point de charger un nouveau fichier de paramétrages sans sauvegarde de vos dernières modifications.\nVoulez vous au préalable sauvegarder le fichier actuellement en édition ? -> " + paramsManager.getName_NoNameIfNull(),
					"Sauvegarde de vos modifications",
					JOptionPane.YES_NO_CANCEL_OPTION,
					JOptionPane.QUESTION_MESSAGE);

			if (reponse == 0) {
				// Demande de sauvegarde
				boolean bSvg = saveParams();

				// si la sauvegarde a été annulée, c'est que finalement, l'utilisateur
				//  ne souhaite plus changer de fichier de param
				//  on annule donc tout
				if (!bSvg) {
					getComboBoxStoredParams().setSelectedItem(paramsManager.getName());
					return;
				}

			} else if (reponse == 1) {
				// Pas de sauvegarde, on poursuit le chargement du nouveau fichier de param
			} else if (reponse == 2) {
				// Annulation du chargement du fichier de param
				// On reselectionne dans le combo le nom du Paramétrage en cours d'édition
				getComboBoxStoredParams().setSelectedItem(paramsManager.getName());
				// on stoppe le chargement
				return;
			}
		}

		STOP_HANDLE_EVENTS();

		// A présent on charge le fichier de param choisi par l'utilisateur
		paramsManager.loadParams(paramNameChosen);
		getComboBoxStoredParams().setSelectedItem(paramsManager.getName());

		START_HANDLE_EVENTS();

	}


	protected boolean saveParams() {

		// si on etait en train d'éditer par ex un textfield, sans appuyer sur Enter
		// il faut que le paramManager ait bien récupéré la valeur du text field dans le component correspondant
		// avant de sauvegarder.
		// Pour cela, on force cette récupération en faisant comme s'il y avait eu une modif utilisateur.
		paramsManager.traiteOneModifUtilisateur();

		STOP_HANDLE_EVENTS();

		boolean bSvg = paramsManager.saveToFile();
		// peut etre un nouveau nom de fichier a été choisi par l'utilisateur
		//  dans le cas ou le Params précédent était sans nom
		// donc on update le combo pour le positionner sur le nom du fichier en cours
		if (bSvg) {
			updateComboListStoredParams();
			getComboBoxStoredParams().setSelectedItem(paramsManager.getName());
		}

		START_HANDLE_EVENTS();

		return bSvg;
	}


	protected void saveParamsAs() {

		// si on etait en train d'éditer par ex un textfield, sans appuyer sur Enter
		// il faut que le paramManager ait bien récupéré la valeur du text field dans le component correspondant
		// avant de sauvegarder.
		// Pour cela, on force cette récupération en faisant comme s'il y avait eu une modif utilisateur.
		paramsManager.traiteOneModifUtilisateur();

		STOP_HANDLE_EVENTS();

		paramsManager.saveToFileAs();
		updateComboListStoredParams();
		getComboBoxStoredParams().setSelectedItem(paramsManager.getName());

		START_HANDLE_EVENTS();
	}

	//**************************************************************************
	//***** Gestion des boutons standard (save, save as etc.             *******
	//**************************************************************************

	private void button_SaveActionPerformed(java.awt.event.ActionEvent evt) {
		saveParams();
	}
	private void button_SaveAsActionPerformed(java.awt.event.ActionEvent evt) {
		saveParamsAs();
	}
	private void button_NewParamsActionPerformed(java.awt.event.ActionEvent evt) {
		// On se contente de sélectionner un param vide dans la combo, la gestion de
		//  l'événement qui va en suivre si chargera de la logique : combo_ListStoredParamsActionPerformed()
		getComboBoxStoredParams().setSelectedItem("");
	}
	private void button_GoActionPerformed(java.awt.event.ActionEvent evt) {
		if (bIsthereError) {
			JOptionPane.showMessageDialog(this, "Il reste des paramètres à corriger", "Paramètres non valides", JOptionPane.ERROR_MESSAGE);
			return;
		}

		// Y a-t-il eu des modif depuis la dernière sauvegarde ?
		if (paramsManager.hasEditUnsaved()) {

			// On demande si l'utilisateur veut sauvegarder ses modif avant le lancement du traitement
			int reponse = JOptionPane.showConfirmDialog(
					this,
					"Vous êtes sur le point de lancer le traitement sans sauvegarde de vos dernières modifications.\nVoulez vous au préalable sauvegarder le fichier actuellement en édition ? -> " + paramsManager.getName_NoNameIfNull(),
					"Sauvegarde de vos modifications",
					JOptionPane.YES_NO_CANCEL_OPTION,
					JOptionPane.QUESTION_MESSAGE);

			if (reponse == 0) {
				// Demande de sauvegarde
				boolean bSvg = saveParams();

				// si la sauvegarde a été annulée, c'est que finalement, l'utilisateur
				//  ne souhaite plus lancer le traitement ...
				//  on annule donc tout
				if (!bSvg)
					return;

			} else if (reponse == 1) {
				// Pas de sauvegarde, on poursuit le chargement du nouveau fichier de param

			} else if (reponse == 2) {
				// Annulation de la demande de traitement
				return;
			}
		}

		// Arrivé là, c'est qu'on doit lancer le traitement
		this.setVisible(false);
		bUserHasCanceled = false;
	}
	private void button_CancelActionPerformed(java.awt.event.ActionEvent evt) {
		bUserHasCanceled = true;
		this.setVisible(false);
	}

	//**************************************************************************
	//***** Gestion Validation / Invalidation des valeurs des paramètres *******
	//**************************************************************************

	//  Les tabs ou le bouton Go seront invalidés ensuite si certains des composants le sont
	public void validateAllTabs() {
		for (int i=0; i<NB_TAB ; i++) {
			list_labelTab[i].setForeground(COLOR_VALID);
			list_labelTab[i].setToolTipText(null);
		}
	}
	private void invalidateTab (int indexTab) {
		list_labelTab[indexTab].setForeground(COLOR_INVALID);

		// TODO_KO ETRANGE : si on met un tool tip, on ne peut plus cliquer sur l'onglet, il ne répond plus !!!
//		list_labelTab[indexTab].setToolTipText("Des erreurs, signalées en rouge sont à corriger dans cet onglet");
	}


	private void invalidateTabOfThisComponent (JComponent comp) {
		if (getTabbedPane() == null) return;

		int indexTab = getTabIndexOfThisComponent(comp);
		if (indexTab != -1)
			invalidateTab(indexTab);
		else
			System.out.println("!!!!!!! Composant non trouvé !!!!!!!");
	}

	private int getTabIndexOfThisComponent(JComponent comp) {
		Container lastContainer = null;
		for(Container p = comp; p != null; p = p.getParent()) {
            if (p instanceof JTabbedPane) {
				JPanel jPanel = (JPanel) lastContainer;
				for (int i = 0; i <getTabbedPane().getComponentCount() ; i++) {
					if (getTabbedPane().getComponentAt(i)==jPanel)
						return i;
				}
			}
			lastContainer = p;
        }
		return -1;
	}

	public void validateGoButton() {
		bIsthereError = false;
//		getGoButton().setEnabled(true);
//		getGoButton().setForeground(COLOR_VALID);
//		getGoButton().setBorder(BorderFactory.createLineBorder(COLOR_VALID, 2));
//		getGoButton().setToolTipText(null);
	}
	private void invalidateGoButton() {
		bIsthereError = true;
//		getGoButton().setEnabled(false);
//		getGoButton().setForeground(COLOR_INVALID);
//		getGoButton().setBorder(BorderFactory.createLineBorder(COLOR_INVALID, 2));
//		getGoButton().setToolTipText("Veuillez corriger d'abord les erreurs signalées en rouge");
	}

	public void validateOrInvalidateComponent(JComponent component, String msgErr, boolean bDrawInvalidBorder) {
		// Dans certains cas, ce n'est pas le même component utilisé pour dessiner
		//  la bordure de couleur que celui pour le tooltip
		// (ex. les JList)
		JComponent componentForBorder;
		JComponent componentForToolTip;

		// Cas standard
		componentForBorder = component;
		componentForToolTip = component;

		// Cas spécial des JList
		if (component instanceof JList &&  component.getParent().getParent() instanceof JScrollPane)
			// component devient le scrollPane qui englobe la liste
			componentForBorder = (JComponent) component.getParent().getParent();


		if (msgErr==null || msgErr.length()==0) {
			// Validation
			if (bDrawInvalidBorder)
				componentForBorder.setBorder(BorderFactory.createLineBorder(COLOR_VALID));
			componentForToolTip.setToolTipText(null);
			// pas besoin de valider le tab, car ils sont tous validés par défaut en début de traitement
			//idem pour le bouton Go

		} else {
			// Invalidation
			if (bDrawInvalidBorder)
				componentForBorder.setBorder(BorderFactory.createLineBorder(COLOR_INVALID));
			componentForToolTip.setToolTipText(msgErr);

			invalidateTabOfThisComponent(component);
			invalidateGoButton();
		}
	}


    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setTitle("Autogene : Ligne-Sites");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents


    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables


}
